/**
 * @(#)SimpleDynamicString.java, 2015年3月28日. 
 * 
 * Copyright 2015 Youdao, Inc. All rights reserved.
 * YOUDAO PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package jadis.data;

import java.util.Arrays;

import com.google.common.base.Preconditions;

import jadis.utils.UnitUtils;

/**
 * A Java-implemented Simple Dynamic String. We treat char[] in C as char[] in
 * Java and C-string as String in Java.
 * 
 * @author yuanwq
 */
public class SimpleDynamicString {
    private static final char[] EMPTY_CHAR_ARRAY = new char[0];
    private static final int MAX_DOUBLE_SPACE_SIZE = (int) UnitUtils.M;

    private int len = 0;
    private int free = 0;
    private char[] buf = null;

    protected SimpleDynamicString(char[] string, int size) {
        Preconditions.checkArgument(size >= 0);
        len = size;
        free = 0;
        mallocAndCopy(string, len + free);
    }

    /**
     * @param string
     * @param i
     */
    protected void mallocAndCopy(char[] string, int size) {
        if (size == 0) {
            buf = EMPTY_CHAR_ARRAY;
        } else {
            string = string == null ? EMPTY_CHAR_ARRAY : string;
            buf = Arrays.copyOf(string, size);
        }
    }

    protected void checkLen(int length) {
        Preconditions.checkArgument(length >= len);
        int size;
        if (length < MAX_DOUBLE_SPACE_SIZE) {
            size = length + length;
        } else {
            size = length + MAX_DOUBLE_SPACE_SIZE;
        }
        mallocAndCopy(buf, size);
        free = size - len;
    }

    public SimpleDynamicString() {
        this(null, 0);
    }

    public SimpleDynamicString(char[] string) {
        this(string, string == null ? 0 : string.length);
    }

    public SimpleDynamicString(String string) {
        this(string.toCharArray(), string.length());
    }

    public SimpleDynamicString(SimpleDynamicString sds) {
        this(sds.buf);
    }

    public void sdsfree() {
        buf = EMPTY_CHAR_ARRAY;
        len = 0;
        free = 0;
    }

    public int sdslen() {
        return len;
    }

    public int sdsavail() {
        return free;
    }

    public SimpleDynamicString sdsdup() {
        return new SimpleDynamicString(buf);
    }

    public void sdsclear() {
        free += len;
        len = 0;
    }

    protected void checkCapacity(int size) {
        if (len + free < size) {
            checkLen(size);
        }
    }

    protected void sdscatlen(char[] string, int length) {
        checkCapacity(len + length);
        System.arraycopy(string, 0, buf, len, length);
        len += length;
        free -= length;
    }

    public void sdscat(String string) {
        sdscatlen(string.toCharArray(), string.length());
    }

    public void sdscatsds(SimpleDynamicString sds) {
        sdscatlen(sds.buf, sds.len);
    }

    protected void sdscpylen(char[] string, int length) {
        checkCapacity(length);
        System.arraycopy(string, 0, buf, 0, length);
        len = length;
    }

    public void sdscpy(String string) {
        sdscpylen(string.toCharArray(), string.length());
    }

    public void sdscpy(SimpleDynamicString string) {
        sdscpylen(string.buf, string.len);
    }

    public void sdsgrowzero(int length) {
        checkCapacity(length);
        len = length;
    }

    public void range(int start, int end) {
        // TODO:
    }
    // TODO: more api for sds

}
